#ifndef LOG_H
#define LOG_H

#include <QApplication>
#include <QReadWriteLock>
#include <QFile>
#include <QThread>

/**
 * @brief The Color class 颜色设置
 */
class ConsoleFont {
public:
    const static int DEFAULT; // 重置颜色设置
    const static int BOLD; // 加粗
    const static int UN_BOLD; // 去粗
    const static int UNDER_LINE; // 下滑线
    const static int GLINT; // 闪烁
    const static int INVERSE;// 反色
    const static int BOLD_2; // 加粗
    const static int NORMAL ; // 正常
    const static int UN_UNDER_LINE; // 去掉下滑线
    const static int STOP_GLINT; // 停止闪烁
    const static int INVERSE_2;// 反色

    const static int FORE_GROUND_BLACK;// 前景，黑色
    const static int FORE_GROUND_RED;// 前景，红色
    const static int FORE_GROUND_GREEN;// 前景，绿色
    const static int FORE_GROUND_ORANGE;// 前景，黄色
    const static int FORE_GROUND_BLUE; //前景，篮色
    const static int FORE_GROUND_PURPLE; //前景，紫色
    const static int FORE_GROUND_CYAN; //前景，青色
    const static int FORE_GROUND_WHITE; //前景，白色

    const static int BACK_GROUND_BLACK;// 背景，黑色
    const static int BACK_GROUND_RED;// 背景，红色
    const static int BACK_GROUND_GREEN;// 背景，绿色
    const static int BACK_GROUND_ORANGE;// 背景，黄色
    const static int BACK_GROUND_BLUE; //背景，篮色
    const static int BACK_GROUND_PURPLE; //背景，紫色
    const static int BACK_GROUND_CYAN; //背景，青色
    const static int BACK_GROUND_WHITE; //背景，白色

    /**
     * @brief setConsoleFont 设置控制台字体样式
     * @param codes 字体样式code集合，用{}设置数组的方式进行传参
     * @param msg 信息
     * @return 设置样式后的内容
     */
    const static QString setConsoleFont(std::initializer_list<int> codes, QString msg);
};

/**
 * @brief The LogType enum 日志输出类型
 */
enum LogOutType {
    STANDARD_OUTPUT, // 标准输出流
    STANDARD_ERROR_OUTPUT // 标准错误输出流
};

/**
 * @brief The LogSwitchoverType enum 日志切换方式（即备份方式）
 */
enum LogSwitchoverType{
    ALL_DAY, // 指定天数备份，即相隔天数的凌晨00:00:00（对应单位是天d）
    TIME_PERIOD, // 指定时间间隔备份，即从项目启动开始后的间隔时间周期（对应单位是秒s）
    FILE_SIZE // 指定文件大小备份（对应单位是kb）
};


/**
 * 回调函数，日志类型、日志上下文，日志所在线程,转化后的日志所在线程信息,日志信息、格式化之后的信息，传入对象上下文
 */
typedef void (*LogInfoCallBackHandler)(QtMsgType, const QMessageLogContext &, QThread *, const QString &, const QString &, const QString &, void *);

/**
 * @brief The CallBackInfo class 回调信息
 */
class CallBackInfo{
public:
    CallBackInfo() {}
    CallBackInfo(QString unique, LogInfoCallBackHandler hander, void* context) {
        this->unique = unique;
        this->hander = hander;
        this->context = context;
    }
    QString unique; // 唯一标识
    LogInfoCallBackHandler hander; // 回调函数
    void* context; // 对象上下文
};

/**
 * 回调信息线程安全集合
 */
class CallBackInfoSafeList{
public:
    CallBackInfoSafeList() {}
    void add(CallBackInfo info){
        QWriteLocker lock(readWriteLock);
        this->mList.append(info);
    }
    QList<CallBackInfo> getList(){
        QReadLocker lock(readWriteLock);
        return mList;
    }
    CallBackInfo get(int index){
        QReadLocker lock(readWriteLock);
        return mList.value(index);
    }
private:
    QList<CallBackInfo> mList; // 回调信息集合
    mutable QReadWriteLock *readWriteLock = new QReadWriteLock(); // 读写锁
};

/**
 * @brief The Log class 日志
 */
class Log
{
public:
    Log() {}
    const static QString INFO_FORMAT_TIME; // 格式化输出日期表示
    const static QString INFO_FORMAT_LEVEL; // 格式化输出日志级别表示
    const static QString INFO_FORMAT_CODE_FILE; // 格式化输出代码文件地址表示
    const static QString INFO_FORMAT_CODE_LINE; // 格式化输出代码所在行表示
    const static QString INFO_FORMAT_CODE_FUNCTION; // 格式化输出代码所在方法函数表示
    const static QString INFO_FORMAT_CODE_MSG; // 格式化输出代码打印内容表示
    const static QString INFO_FORMAT_THREAD; // 格式化输出线程地址表示

    /**
     * @brief setFormat 设置日志输出内容格式化
     * @param infoFormat 内容格式化参数
     * @param timeFormat 日期格式化
     */
    static void setFormat(QString infoFormat, QString timeFormat = "yyyy-MM-dd hh:mm:ss:zzz");
    /**
     * @brief setLevelColor 设置不同日志级别的字体格式
     * @param type 日志类型
     * @param levelColor 字体格式
     */
    static void setLevelFont(QtMsgType type, std::initializer_list<int> levelFont);
    /**
     * @brief setOutLogPath 设置输出地址
     * @param outLogPath 日志输出地址
     */
    static void setOutLogPath(QString outLogPath);
    /**
     * @brief setOutLogParamPath 设置日志备份参数json存储地址
     * @param logParamPath 日志备份参数json存储地址
     */
    static void setOutLogParamJsonPath(QString logParamJsonPath);
    /**
     * @brief setLogSwitchover 设置日志切换备份方式
     * @param logSwitchoverType 日志备份类型
     * @param switchoverNum 备份时间或大小（ALL_DAY则是天数;TIME_PERIOD是时间间隔，单位秒;FILE_SIZE是文件大小，单位时kb）
     */
    static void setLogSwitchover(LogSwitchoverType logSwitchoverType, long long switchoverNum);
    /**
     * @brief setDistinguishLevel 设置备份输出是否区分日志级别单独输出
     * @param isDistinguishLevel 是否区分
     */
    static void setDistinguishLevel(bool isDistinguishLevel);
    /**
     * @brief messageOutput 日志输出注册函数
     * @param type 日志信息类型
     * @param context 日志信息上下文
     * @param msg 输出内容信息
     */
    static void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
    /**
     * @brief registLogInfoCallBack 注册回调函数，注册函数使用链式调用，只要注册的函数都会进行调用
     * @param unique 唯一标识
     * @param hander 回调函数
     * @param contex 上下文，可以传入自己想操作的对象
     * @return
     */
    static LogInfoCallBackHandler registLogInfoCallBack(QString unique, LogInfoCallBackHandler hander,void* context = nullptr);
private:
    /**
     * @brief msgTypeMap 日志类型与标识、输出类型映射
     */
    static QMap<QtMsgType,QPair<QString, LogOutType>> msgTypeMap;
    /**
     * @brief levelFontMap 针对不同日志级别的字体显示设置映射
     */
    static QMap<QtMsgType,std::initializer_list<int>> levelFontMap;
    /**
     * @brief logSwitchoverTypeMap 备份类型与字符的映射
     */
    static QMap<LogSwitchoverType, QString> logSwitchoverTypeMap;
    /**
     * @brief outLogFile 输出file
     */
    static QFile* outLogFile;
    /**
     * @brief levelPaths 不同级别对应的输出路径
     */
    static QMap<QtMsgType, QFile*> levelPaths;
    /**
     * @brief isDistinguishLevel 是否区分日志级别输出
     */
    static bool isDistinguishLevel;
    /**
     * @brief infoFormat 日志输出内容格式化参数
     */
    static QString infoFormat;
    /**
     * @brief timeFormat 日期格式
     */
    static QString timeFormat;
    /**
     * @brief logParamJsonFile 日志备份策略参数保存json文件
     */
    static QFile* logParamJsonFile;
    /**
     * @brief logSwitchoverType 指定备份类型
     */
    static LogSwitchoverType logSwitchoverType;
    /**
     * @brief switchoverNum 指定备份时间或大小
     */
    static long long switchoverNum;
    /**
     * @brief switchoverTime 备份切换时间
     */
    static QDateTime switchoverTime;
    /**
     * @brief isLoadLogSwitchoverSetting 是否加载备份日志设置
     */
    static bool isLoadLogSwitchoverSetting;
    /**
     * @brief pCallback 存放回调函数的集合
     */
    static CallBackInfoSafeList pCallbacks;


    /**
     * @brief initMsgTypeMap 初始化日志类型与标识、输出类型映射
     * @return 日志类型与标识、输出类型映射
     */
    static QMap<QtMsgType,QPair<QString, LogOutType>> initMsgTypeMap();
    /**
     * @brief initLevelColors 初始化不同日志级别的字体显示设置映射
     */
    static QMap<QtMsgType,std::initializer_list<int>> initLevelFonts();
    /**
     * @brief initLogSwitchoverTypeMap 初始化备份类型与字符的映射
     */
    static QMap<LogSwitchoverType, QString> initLogSwitchoverTypeMap();
    /**
     * @brief writeLog 输出日志内容到文件
     * @param str 日志内容
     * @param QtMsgType 日志类型
     */
    static void writeLog(QString str, QtMsgType msgType);
    /**
     * @brief loadLogSwitchoverSetting 加载日志备份设置
     */
    static void loadLogSwitchoverSetting();
    /**
     * @brief logSwitchoverSettingHander 日志备份设置处理
     */
    static void logSwitchoverSettingHander();
    /**
     * @brief writeLogParamJson 向json文件中写入备份参数
     */
    static void writeLogParamJson();
    /**
     * @brief copyLogOutFile 备份日志文件
     */
    static void copyLogOutFile(QtMsgType msgType);
    /**
     * @brief copy 拷贝文件，目标文件存在则覆盖
     * @param srcFilepPath 源文件
     * @param targetFilePath 目标文件
     * @param 拷贝成功与否
     */
    static bool copy(QString srcFilepPath, QString targetFilePath);
    /**
     * @brief replace 替换字符串
     * @param src 原字符串
     * @param before 被替换的字符串
     * @param after 替换字符串
     * @return 被替换之后的字符串
     */
    static QString replace(QString src, QString before, QString after);
    /**
     * @brief isContainInfoFormat 判断是否包含格式化信息
     * @return 包含与否
     */
    static bool isContainInfoFormat(QString mInfoFormat = "");
    /**
     * @brief printSystemLog 打印日志系统自身的提示信息
     * @param level 级别（普通info，警告warn,错误error）
     * @param msg 信息
     * @return
     */
    static void printSystemLog(QString level, QString msg);
};

class LogThread : public QThread
{
    Q_OBJECT
    void run() override {
//        qDebug()<<"测试线程：["<<quintptr(QThread::currentThreadId())<<" "<<quintptr(QThread::currentThread())<<"]";
//        qDebug()<<"测试线程3：["<<QThread::currentThreadId()<<" "<<QThread::currentThread()<<"]";
    }
signals:

};

#endif // LOG_H
